package org.hcyspartnoc.luoxin.service.chat.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.hcyspartnoc.luoxin.common.core.PageBean;
import org.hcyspartnoc.luoxin.common.core.configuration.ServiceConfiguration;
import org.hcyspartnoc.luoxin.common.core.context.BaseContextHolder;
import org.hcyspartnoc.luoxin.common.enums.chat.ChatMessageTypeEnum;
import org.hcyspartnoc.luoxin.common.enums.chat.ChatSenderTypeEnum;
import org.hcyspartnoc.luoxin.common.exception.chat.ChatMessageException;
import org.hcyspartnoc.luoxin.common.exception.framework.AuthException;
import org.hcyspartnoc.luoxin.mapper.chat.ChatCounselingSessionMapper;
import org.hcyspartnoc.luoxin.mapper.chat.ChatMessageMapper;
import org.hcyspartnoc.luoxin.mapper.chat.ChatSessionUserMapper;
import org.hcyspartnoc.luoxin.mapper.service.ServiceCounselorOrderMapper;
import org.hcyspartnoc.luoxin.pojo.dto.chat.ChatMessageLikeDto;
import org.hcyspartnoc.luoxin.pojo.po.chat.ChatCounselingSessionPo;
import org.hcyspartnoc.luoxin.pojo.po.chat.ChatMessagePo;
import org.hcyspartnoc.luoxin.pojo.po.chat.ChatSessionUserPo;
import org.hcyspartnoc.luoxin.pojo.po.service.ServiceCounselorOrderPo;
import org.hcyspartnoc.luoxin.pojo.vo.chat.ChatMessageVo;
import org.hcyspartnoc.luoxin.service.chat.IChatMessageService;
import org.hcyspartnoc.luoxin.service.service.impl.ServiceCounselorOrderServiceImpl;
import org.hcyspartnoc.luoxin.utils.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Service
public class ChatMessageServiceImpl extends ServiceImpl<ChatMessageMapper, ChatMessagePo>
        implements IChatMessageService {
    @Resource
    private ServiceConfiguration serviceConfiguration;
    @Resource
    private ChatMessageMapper chatMessageMapper;
    @Resource
    private ServiceCounselorOrderMapper serviceCounselorOrderMapper;
    @Resource
    private ChatSessionUserMapper chatSessionUserMapper;
    @Resource
    private ChatCounselingSessionMapper chatCounselingSessionMapper;

    @Override
    public PageBean<ChatMessagePo, ChatMessageVo> queryPageByToken(int currentPage, int pageSize, String sessionId) throws AuthException {


        MPJLambdaWrapper<ChatMessagePo> wrapper;
        List<String> messageIds = new ArrayList<>();
        messageIds.add(sessionId);
        if (sessionId.length() == 32) { // 获取主会话消息和子会话消息
            // 校验该会话id是否和该用户有关联
            if (!chatSessionUserMapper.exists(new LambdaQueryWrapper<>(ChatSessionUserPo.class)
                    .eq(ChatSessionUserPo::getSessionId, sessionId)
                    .eq(ChatSessionUserPo::getUserId, BaseContextHolder.getContext().getBaseCurrentUser().getId())))
                throw new AuthException(AuthException.PERMISSION_NOT_ENOUGH);
            // 获取子会话id
            for (ChatCounselingSessionPo po : chatCounselingSessionMapper.selectList(new LambdaQueryWrapper<>(ChatCounselingSessionPo.class)
                    .eq(ChatCounselingSessionPo::getMasterSessionId, sessionId)))
                messageIds.add(po.getId().toString());
            wrapper = new MPJLambdaWrapper<ChatMessagePo>()
                    .in(ChatMessagePo::getSessionId, messageIds)
                    .gt(ChatMessagePo::getSendTime, LocalDateTime.now().minus(Duration.ofSeconds(serviceConfiguration.getChat().getMessageExpires())))
                    .orderByDesc(ChatMessagePo::getSendTime);
        } else {
            // 校验该会话id是否和该用户有关联
            int intSessionId;
            try {
                intSessionId = Integer.parseInt(sessionId);
            } catch (Exception ignore) {
                throw new AuthException(AuthException.PERMISSION_NOT_ENOUGH);
            }
            if (!chatCounselingSessionMapper.exists(new LambdaQueryWrapper<>(ChatCounselingSessionPo.class)
                    .eq(ChatCounselingSessionPo::getUserId, BaseContextHolder.getContext().getBaseCurrentUser().getId())
                    .eq(ChatCounselingSessionPo::getId, intSessionId)))
                throw new AuthException(AuthException.PERMISSION_NOT_ENOUGH);
            wrapper = new MPJLambdaWrapper<ChatMessagePo>()
                    .in(ChatMessagePo::getSessionId, messageIds)
                    .gt(ChatMessagePo::getSendTime, LocalDateTime.now().minus(Duration.ofSeconds(serviceConfiguration.getChat().getMessageExpires())));
        }

        Page<ChatMessagePo> page = new Page<>(currentPage, pageSize);
        chatMessageMapper.selectPage(page, wrapper);
        ArrayList<ChatMessageVo> chatMessageVos = new ArrayList<>();
        for (ChatMessagePo chatMessagePo : page.getRecords()) {
            ChatMessageVo chatMessageVo = chatMessagePoToVo(chatMessagePo);
            chatMessageVo.setSessionId(sessionId);// 将子会话的会话id隐藏为主会话id
            chatMessageVos.add(chatMessageVo);
        }
        return new PageBean<>(page, chatMessageVos);
    }

    @Override
    @Transactional
    public void modifyLike(ChatMessageLikeDto chatMessageLikeDto) throws ChatMessageException, AuthException {
        // 查询消息是否存在
        ChatMessagePo chatMessagePo = messageNotExistsThrow(chatMessageLikeDto.getMessageId());
        // 如果消息是虚拟咨询师发送的
        if (Objects.equals(ChatSenderTypeEnum.fromCode(chatMessagePo.getSenderType()), ChatSenderTypeEnum.V_COUNSELOR)) {
            // 查询该消息的联系人是否是当前用户
            if (!chatMessagePo.getContactId().equals(BaseContextHolder.getContext().getBaseCurrentUser().getId()))
                throw new AuthException(AuthException.PERMISSION_NOT_ENOUGH);
            chatMessagePo.setIsLike(chatMessageLikeDto.getLikeStatus());
            Db.saveOrUpdate(chatMessagePo);
        } else {
            throw new ChatMessageException(ChatMessageException.MESSAGE_COUNT_NOT_LIKE);
        }
    }

    @Override
    @Transactional
    public void removeMessage(Long messageId) throws ChatMessageException, AuthException {
        ChatMessagePo chatMessagePo = messageNotExistsThrow(messageId);
        // 消息是该用户发送的/消息是机器人发送的并且该用户是接收者
        boolean condition1 = chatMessagePo.getSenderId().equals(BaseContextHolder.getContext().getBaseCurrentUser().getId())
                && chatMessagePo.getSenderType().equals(ChatSenderTypeEnum.USER.getCode());
        boolean condition2 = (Objects.equals(ChatSenderTypeEnum.fromCode(chatMessagePo.getSenderType()), ChatSenderTypeEnum.V_COUNSELOR)
                && chatMessagePo.getContactId().equals(BaseContextHolder.getContext().getBaseCurrentUser().getId()));
        if (condition1 || condition2) {
            removeById(messageId);
        } else {
            throw new AuthException(AuthException.PERMISSION_NOT_ENOUGH);
        }

    }

    public ChatMessageVo chatMessagePoToVo(ChatMessagePo po) {
        ChatMessageVo chatMessageVo = BeanUtil.copyProperties(po, ChatMessageVo.class);
        chatMessageVo.setFormatSendTime(StringUtils.formatDateTime(po.getSendTime()));
        // 如果消息类型为NEW_ORDER_SESSION,将订单信息写入额外信息中
        if (Objects.equals(ChatMessageTypeEnum.fromCode(po.getMessageType()), ChatMessageTypeEnum.ORDER_SESSION_START)) {
            ServiceCounselorOrderPo serviceCounselorOrderPo = serviceCounselorOrderMapper.selectOne(new LambdaQueryWrapper<>(ServiceCounselorOrderPo.class)
                    .eq(ServiceCounselorOrderPo::getSessionId, Integer.parseInt(po.getMessageContent())));
            chatMessageVo.setExtraInfo(ServiceCounselorOrderServiceImpl.ServiceCounselorOrderPoToVo(serviceCounselorOrderPo));
        }
        return chatMessageVo;
    }

    public ChatMessagePo messageNotExistsThrow(Long messageId) throws ChatMessageException {
        ChatMessagePo chatMessagePo = chatMessageMapper.selectById(messageId);
        if (Objects.isNull(chatMessagePo))
            throw new ChatMessageException(ChatMessageException.MESSAGE_NOT_EXISTS);
        return chatMessagePo;
    }
}
